package com.syh.jn.scm.infrastructure.repository.impl.supplier.stock;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.jn.scm.domain.supplier.entity.stock.StockLoss;
import com.syh.jn.scm.domain.supplier.entity.stock.StockLossItem;
import com.syh.jn.scm.domain.supplier.repository.stock.StockLossRepository;
import com.syh.jn.scm.dto.supplier.stock.StockLossItemVo;
import com.syh.jn.scm.dto.supplier.stock.StockLossVo;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsBrandModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsCategoryModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsModel;
import com.syh.jn.scm.infrastructure.repository.model.stock.stockLoss.StockLossItemModel;
import com.syh.jn.scm.infrastructure.repository.model.stock.stockLoss.StockLossModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报损单管理
 */
@Repository
public class StockLossRepositoryImpl extends AbstractAggregateRepository<StockLoss, StockLossModel, Long> implements StockLossRepository {
  /**
   * 重写add方法
   *
   * @param loss
   * @return
   */
  @Override
  public Long add(StockLoss loss) {
    //保存报损单基础信息
    StockLossModel stockLossModel = new StockLossModel();
    ExtBeanUtils.copyProperties(loss, stockLossModel);

    //添加报损单基础信息成功返回id
    Long lossOrderId = (Long) this.hibernateTemplate.save(stockLossModel);

    //保存当前报损单对应的报损单项
    this.saveLossOrderItems(lossOrderId, loss.getLossItems());

    return lossOrderId;
  }

  /**
   * 重写remove方法
   *
   * @param loss
   */
  @Override
  public void remove(StockLoss loss) {
    //删除报损单基础数据
    super.removeById(loss.getId());
    //删除符合条件的报损单项
    this.removeItem(loss);
  }

  /**
   * 重写update方法
   *
   * @param loss
   */
  @Override
  public void update(StockLoss loss) {
    //修改报损单基础数据
    super.update(loss);
    //删除符合条件的报损单项
    this.removeItem(loss);
    //存储新的报损单项
    this.saveLossOrderItems(loss.getId(), loss.getLossItems());
  }

  /**
   * 重写getById
   *
   * @param id
   * @return
   */
  @Override
  public StockLoss getById(Long id) {
    StockLoss stockLoss = super.getById(id);

    if (stockLoss == null) {
      return stockLoss;
    }

    String hql = "from StockLossItemModel model where model.lossOrderId = ?";
    List<StockLossItemModel> itemModelList = (List<StockLossItemModel>) this.hibernateTemplate.find(hql, id);
    List<StockLossItem> itemList = new ArrayList<>();
    itemModelList.stream().forEach(itemModel -> {
      StockLossItem stockLossItem = new StockLossItem();
      ExtBeanUtils.copyProperties(itemModel, stockLossItem);
      itemList.add(stockLossItem);
    });
    stockLoss.setLossItems(itemList);
    return stockLoss;
  }

  /**
   * 更新报损单状态
   *
   * @param loss
   */
  @Override
  public void updateStatus(StockLoss loss) {
    super.update(loss);
  }

  /**
   * 保存当前报损单对应的报损单项
   *
   * @param lossOrderId 报损单id
   * @param items       当前报损单所对应的报损单项集合
   */
  private void saveLossOrderItems(Long lossOrderId, List<StockLossItem> items) {
    //保存报损单项
    items.stream().forEach(item -> {
      StockLossItemModel stockLossItemModel = new StockLossItemModel();
      GoodsModel goodsModel = this.hibernateTemplate.get(GoodsModel.class, item.getGoodsId());
      GoodsCategoryModel goodsCategoryModel = new GoodsCategoryModel();
      if (goodsModel.getCategoryId() != null) {
        goodsCategoryModel = this.hibernateTemplate.get(GoodsCategoryModel.class, goodsModel.getCategoryId());
      }
      GoodsBrandModel goodsBrandModel = new GoodsBrandModel();
      if (goodsModel.getGoodsBrandId() != null) {
        goodsBrandModel = this.hibernateTemplate.get(GoodsBrandModel.class, goodsModel.getGoodsBrandId());
      }
      StockLossModel stockLossModel = this.hibernateTemplate.get(StockLossModel.class, lossOrderId);

      ExtBeanUtils.copyProperties(item, stockLossItemModel);
      stockLossItemModel.setLossOrderId(lossOrderId);
      stockLossItemModel.setBusinessEntityId(stockLossModel.getBusinessEntityId());
      //在仓储层冗余是为了安全和数据的准确
      stockLossItemModel.setGoodsName(goodsModel.getName());
      stockLossItemModel.setConversionRate(goodsModel.getConversionRate());
      stockLossItemModel.setCode(goodsModel.getCode());
      stockLossItemModel.setSpecName(goodsModel.getSpecName());
      stockLossItemModel.setConversionRate(goodsModel.getConversionRate());
      stockLossItemModel.setUnits(goodsModel.getUnits());
      stockLossItemModel.setCategoryId(goodsModel.getCategoryId());
      stockLossItemModel.setCategoryName(goodsCategoryModel.getName());
      stockLossItemModel.setCategoryCatalogCode(goodsCategoryModel.getCatalogCode());
      stockLossItemModel.setGoodsBrandId(goodsBrandModel.getId());
      stockLossItemModel.setGoodsBrandName(goodsBrandModel.getName());
      this.hibernateTemplate.save(stockLossItemModel);
    });
  }

  /**
   * 删除符合条件的报损单项
   *
   * @param loss
   */
  private void removeItem(StockLoss loss) {
    //根据lossOrderId查找报损项
    StringBuffer hql = new StringBuffer();
    hql.append("from StockLossItemModel model where model.lossOrderId = ?");
    List<StockLossItemModel> itemModelList = (List<StockLossItemModel>) this.hibernateTemplate.find(hql.toString(), loss.getId());

    //删除所有符合要求的报损项
    itemModelList.stream().forEach(lossItem -> {
      this.hibernateTemplate.delete(lossItem);
    });
  }

  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(
              "DISTINCT loss.ID",
              SQLAliasGenerateUtil.aliasGenerate(StockLossModel.class, "loss", null),
              "s.NAME AS storehouseName,account.NAME AS operatorName"
      );
      FROM("T_STOCK_STOCK_LOSS loss");
      LEFT_OUTER_JOIN("T_BASE_STOREHOUSE s on loss.STOREHOUSE_ID = s.ID");
      LEFT_OUTER_JOIN("T_STOCK_STOCK_LOSS_ITEM item ON item.LOSS_ORDER_ID = loss.ID");
      LEFT_OUTER_JOIN("T_SYSTEM_ACCOUNT account ON account.ID = loss.OPERATOR_ID");
    }};
  }

  @Override
  public int getCountView(Wrapper wrapper) {
    StringBuffer sqlSb = new StringBuffer();
    String viewSql = this.getViewSql().toString();

    String viewSqlAry[] = viewSql.split("\\s*FROM\\s*");
    sqlSb.append("SELECT COUNT(DISTINCT loss.ID) AS COUNT FROM ");
    for (int i = 1; i <= viewSqlAry.length - 1; i++) {
      if (i > 1) {
        sqlSb.append(" FROM ").append(viewSqlAry[i]);
      } else {
        sqlSb.append(viewSqlAry[i]);
      }
    }
    BaseResolve resolveToSQL = this.getViewWrapperResolve(wrapper);
    sqlSb.append(" WHERE 1=1 ");
    sqlSb.append(resolveToSQL.resolve());

    Map resultM = MybatisTemplate.selectOne(sqlSb.toString());
    return Integer.parseInt(resultM.get("COUNT").toString());
  }

  /**
   * 根据报损单id获取报损单明细
   * @param id
   * @return
   */
  @Override
  public List<StockLossItemVo> getItemVosById(Long id) {
    String hql = "from StockLossItemModel model where model.lossOrderId = ? ";
    List<StockLossItemModel> modelList = (List<StockLossItemModel>) this.hibernateTemplate.find(hql, id);
    List<StockLossItemVo> itemVos = new ArrayList<>();
    if (modelList != null && modelList.size() > 0) {
      for (StockLossItemModel itemModel : modelList) {
        StockLossItemVo item= new StockLossItemVo();
        ExtBeanUtils.copyProperties(itemModel, item);
        itemVos.add(item);
      }
    }
    return itemVos;
  }

  /**
   * 根据服务商id删除采购单
   * @param businessEntityId
   */
  @Override
  public void deleteByBusinessEntityId(Long businessEntityId) {
    String itemHql = "delete from StockLossItemModel where businessEntityId = :businessEntityId";
    Query itemQuery = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(itemHql);
    itemQuery.setParameter("businessEntityId",businessEntityId);
    itemQuery.executeUpdate();
    String orderHql = "delete from StockLossModel where businessEntityId = :businessEntityId";
    Query orderQuery = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(orderHql);
    orderQuery.setParameter("businessEntityId",businessEntityId);
    orderQuery.executeUpdate();
  }

  @Override
  protected Class getViewObject() {
    return StockLossVo.class;
  }

  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    HashMap<String, String> weMap = new HashMap<>();
    weMap.put("status", "loss.STATUS");
    weMap.put("id", "loss.ID");
    weMap.put("lossOrderCode", "loss.LOSS_ORDER_CODE");
    weMap.put("originalOrderCode", "loss.ORIGINAL_ORDER_CODE");
    weMap.put("lossDateTimestamp", "loss.LOSS_DATE_TIMESTAMP");
    weMap.put("lossType", "loss.LOSS_TYPE");
    weMap.put("storehouseId", "loss.STOREHOUSE_ID");
    weMap.put("businessEntityId", "loss.BUSINESS_ENTITY_ID");
    weMap.put("goodsId", "item.GOODS_ID");
    weMap.put("goodsName", "item.GOODS_NAME");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return weMap.get(propertyName);
    });
    return parse;
  }

  /**
   * 判断报损项是否存在该商品
   *
   * @param column
   * @param id
   * @return
   */
  @Override
  public boolean stockLossItemExistsById(String column, Long id) {
    StringBuffer hql = new StringBuffer("SELECT COUNT(*) FROM StockLossItemModel where ").append(column).append(" = ").append(id);
    this.getLogger().debug(hql.toString());
    Query query = buildQuery(hql);
    return ((Long) query.uniqueResult()).intValue() > 0;
  }

  /**
   * 获取明细对象
   *
   * @param id      明细id
   * @param goodsId 明细商品id
   * @return
   */
  @Override
  public StockLossItem getItemByIdAndGoodsId(Long id, Long goodsId) {
    String hql = "from StockLossItemModel model where model.id = ? and model.goodsId = ?";
    List<StockLossItemModel> modelList = (List<StockLossItemModel>) this.hibernateTemplate.find(hql, id, goodsId);
    StockLossItem item = null;
    if (modelList != null && modelList.size() > 0) {
      for (StockLossItemModel itemModel : modelList) {
        item = new StockLossItem();
        ExtBeanUtils.copyProperties(itemModel, item);
      }
    }
    return item;
  }
}
